package com.aps.algorithm.heuristic;


import com.aps.algorithm.core.AlgorithmParameters;
import com.aps.algorithm.heuristic.genetic.dto.ApsOperationDto;
import com.aps.algorithm.heuristic.genetic.model.Chromosome;
import com.aps.algorithm.utils.output.OutputUtils;
import com.aps.common.constant.Constants;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author jsy
 * @description:遗传算法策略抽象类，这里面的方法都是默认的
 * @date 2025/9/28 15:29
 */
@Slf4j
public abstract class GeneticAlgorithmStrategy extends GeneticAlgorithm {
    private final Logger logger = LoggerFactory.getLogger(GeneticAlgorithmStrategy.class);

    /**
     * @description: 获取策略类型
     * @author: jsy
     * @time: 2025/9/29 10:07
     */
    protected abstract String getStrategyType();

    /**
     * @description: 计算单个染色体的适应度
     * @author: jsy
     * @time: 2025/9/29 10:07
     */
    protected abstract double calSingleChromosome(GeneticStrategyParams params);

    /**
     * @description: 传入算法参数
     * @author: jsy
     * @time: 2025/9/29 10:06
     */
    protected abstract void setParameters(AlgorithmParameters parameters);

    /**
     * @description: 选择父代（精英+锦标赛）
     * @author: jsy
     * @time: 2025/9/29 10:06
     */
    protected List<Chromosome<ApsOperationDto>> selectParents(List<Chromosome<ApsOperationDto>> population) {
        List<Chromosome<ApsOperationDto>> parents = new ArrayList<>();
        // 按适应度排序（降序）
//        population.sort(Comparator.comparingDouble(Chromosome::getFitness).reversed());
        population.sort((c1, c2) -> Double.compare(c2.getFitness(), c1.getFitness()));
        // 精英选择
        int eliteSize = new BigDecimal((Long) this.parameters.getParameter(Constants.POPULATION_SIZE))
                .multiply(new BigDecimal((double) this.parameters.getParameter(Constants.ELITE_RATIO))).intValue();
        for (int i = 0; i < eliteSize; i++) {
            parents.add(population.get(i).copy());
        }

        // 锦标赛选择补充剩余父代
        while (parents.size() < (Long) this.parameters.getParameter(Constants.POPULATION_SIZE)) {
            // 随机选择锦标赛参与者
            List<Chromosome<ApsOperationDto>> tournament = new ArrayList<>();
            for (int i = 0; i < (int) this.parameters.getParameter(Constants.TOURNAMENT_SIZE); i++) {
                int randomIdx = new SecureRandom().nextInt(population.size());
                tournament.add(population.get(randomIdx));
            }

            // 选择锦标赛中适应度最好的个体
            Chromosome<ApsOperationDto> winner = tournament.get(0);
            double bestTournamentFitness = winner.getFitness();
            for (Chromosome<ApsOperationDto> ind : tournament) {
                double fitness = ind.getFitness();
                if (fitness < bestTournamentFitness) {
                    bestTournamentFitness = fitness;
                    winner = ind;
                }
            }
            parents.add(winner.copy());
        }
        return parents;
    }

    /**
     * @description: 变异-机器替换变异 + 插入 / 交换变异（组合使用）
     * random.nextDouble() < mutationRate 是通过随机数与变异概率的比较，来决定是否执行变异操作
     * 遗传算法中，变异不能 “必然发生” 或 “永不发生”
     * 若必然发生（比如直接执行变异，不做概率判断），会破坏种群中已有的优质基因，导致算法不稳定
     * 若永不发生，种群多样性会逐渐丧失，容易陷入局部最优
     * @author: jsy
     * @time: 2025/10/3 16:13
     */
    protected void mutate(Chromosome<ApsOperationDto> chromosome,List<Chromosome<ApsOperationDto>> solutionMutateResults) {
        SecureRandom random = new SecureRandom();
        // 先执行工序顺序变异（50%概率选择插入或交换变异）
        //random.nextDouble() 会生成一个 [0.0, 1.0) 区间的随机小数（包含 0.0，不包含 1.0）
        if (random.nextDouble() < (double) this.parameters.getParameter(Constants.MUTATION_RATE)) {
            if (random.nextBoolean()) {
                insertionMutation(chromosome, random);
            } else {
                swapMutation(chromosome, random);
            }
            //变异后的染色体序列
            OutputUtils.output(chromosome.getGeneSequence(), "变异后的染色体序列");
            //验证基因编码中是否存在重复
            validateNoDuplicates(chromosome.getGeneSequence());
        }
        // 重新生成 chromosomeCode（关键！变异后编码会变，必须重新计算）
        chromosome.preparedChromosomeCode();
        boolean b = addIfCodeNotDuplicate(solutionMutateResults, chromosome);
        if(!b){
            mutate(chromosome,solutionMutateResults);
        }
    }

    /**
     * @description: 插入变异：随机选择一个工序插入到新位置
     * @author: jsy
     * @time: 2025/10/4 16:02
     */
    protected void insertionMutation(Chromosome<ApsOperationDto> chromosome, SecureRandom random) {
        List<ApsOperationDto> sequence = chromosome.getGeneSequence();
        int size = sequence.size();
        if (size <= 1) return;
        // 随机选择一个工序
        int pos1 = random.nextInt(size);
        ApsOperationDto op = sequence.get(pos1);

        // 随机选择一个新位置
        int pos2;
        do {
            pos2 = random.nextInt(size);
        } while (pos1 == pos2);

        // 移除并插入
        sequence.remove(pos1);
        sequence.add(pos2, op);

        // 修复可能的工序顺序问题
        repairOperationSequence(sequence);
    }

    /**
     * @description: 交换变异：随机交换两个工序的位置
     * @author: jsy
     * @time: 2025/10/4 16:02
     */
    protected void swapMutation(Chromosome<ApsOperationDto> chromosome, SecureRandom random) {
        List<ApsOperationDto> sequence = chromosome.getGeneSequence();
        int size = sequence.size();
        if (size <= 1) return;

        // 随机选择两个不同的位置
        int pos1 = random.nextInt(size);
        int pos2;
        do {
            pos2 = random.nextInt(size);
        } while (pos1 == pos2);

        // 交换位置
        Collections.swap(sequence, pos1, pos2);

        // 修复可能的工序顺序问题
        repairOperationSequence(sequence);
    }

    //TODO 别删除
//    /**
//     * @description: 选择父代（锦标赛选择）
//     * @author: jsy
//     * @time: 2025/9/23 16:30
//     */
//    @Override
//    protected List<Chromosome> selectParents(List<Chromosome> population) {
//        List<Chromosome> parents = new ArrayList<>();
//
//        for (int i = 0; i < (int) this.parameters.getParameter(Constants.POPULATION_SIZE); i++) {
//            Chromosome best = null;
//            for (int j = 0; j < (int) this.parameters.getParameter(Constants.TOURNAMENT_SIZE); j++) {
//                int randomIdx = new SecureRandom().nextInt(population.size());
//                Chromosome candidate = population.get(randomIdx);
//                if (best == null || candidate.getFitness() > best.getFitness()) {
//                    best = candidate;
//                }
//            }
//            parents.add(best.copy());
//        }
//
//        return parents;
//    }
}
